<?php
declare (strict_types=1);

namespace app\user\logic\user;

use app\common\exception\LogicException;
use app\user\model\user\Face as FaceModel;
use app\user\tools\tencent\Face as TencentFace;
use eduline\upload\Client as FileClient;
use think\{db\exception\DataNotFoundException,
    db\exception\DbException,
    db\exception\ModelNotFoundException,
    File,
    Request};
use think\exception\FileException;
use Throwable;

/**
 * 人脸验证
 */
class Face extends FaceModel
{
    // /**
    //  * 获取人员库信息
    //  */
    // public function getGroupInfo($param)
    // {
    //     // 验证数据
    //     // $this->getValidate()->scene('face_group_info')->failException()->check($param);
    //     // 请求
    //     return app(TencentFace::class)->getGroupInfo($param);
    // }

    /**
     * 用户已绑定人脸
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-11-29
     *
     * @return boolean [description]
     */
    public function hasUserFaceExist(): bool
    {
        $data = $this->scope('mid')->findOrEmpty();
        return !$data->isEmpty();
    }

    /**
     * 获取人员库信息
     */
    public function createPerson(Request $request)
    {
        // 检查用户是否绑定人脸
        $exist = $this->hasUserFaceExist();
        if ($exist) throw new LogicException('已绑定人脸');
        // 上传并绑定
        try {
            // 上传文件并返回附件信息
            $file = $this->uploadFile($request);
            // 文件保存路径
            $path = $file->filepath;
            // 图片base64值
            $fp = fopen($path, 'r');
            if (!$fp) throw new LogicException('上传错误');
            $gambar = fread($fp, filesize($path));
            fclose($fp);
            //获取图片base64 
            $param['Image'] = chunk_split(base64_encode($gambar));

            /** @var TencentFace $tencentFace */
            $tencentFace = app(TencentFace::class);
            $person      = $tencentFace->createPerson($param);
            if (!$person->FaceId || $person->SimilarPersonId) throw new LogicException('绑定失败');

            $create = $this::create([
                'user_id'   => request()->mid,
                'face_id'   => $person->FaceId,
                'attach_id' => $file->id,
            ]);

            if ($create->isEmpty()) throw new LogicException('绑定失败');

        } catch (FileException $e) {
            // 上传失败获取错误信息
            throw new LogicException($e->getMessage());
        }
    }

    /**
     * 上传文件并返回附件信息
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-11-29
     */
    protected function uploadFile(Request $request)
    {
        // 获取表单上传文件 例如上传了001.jpg
        $file = $request->file('file');
        // 
        if (!$file) throw new LogicException('请上传照片');
        // 
        $filename = $request->has('name', 'post') ? $request->post('name') : $file->getOriginalName();
        // 
        if (!$filename) throw new LogicException('文件名不正确');
        // 存在文件
        $attach = $this->checkFileExist($file);
        if ($attach) return $attach;
        // 
        $extension = strtolower(substr(strrchr($filename, '.'), 1));
        $savename  = md5(microtime()) . '.' . $extension;
        $date      = date('Ymd');
        // 上传
        $client = new FileClient('local');
        $client->putFile('/' . $date, $file, $savename);
        // 载入
        $savepath = app(FacePic::class)->getUploadPath();

        $outfile = $savepath . $date . DIRECTORY_SEPARATOR . $savename;
        $file    = new File($outfile);
        $info    = app(FacePic::class)->saveFacePic($file, ['filename' => $filename]);

        if ($info) return $info->append(['fileurl']);

        throw new LogicException('上传错误');
    }

    /**
     * 检查文件是否已上传，已上传返回附件
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-09-16
     *
     * @param  [type] $file [description]
     */
    protected function checkFileExist($file)
    {
        $filemd5 = $file->md5();
        $attach  = app(FacePic::class)->where('filemd5', $filemd5)->findOrEmpty()->append(['filepath']);
        return $attach->isEmpty() ? null : $attach;
    }

    /**
     * 人员验证
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/12/2
     *
     * @param Request $request
     * @param bool    $createLog
     */
    public function verifyPerson(Request $request, bool $createLog = true)
    {
        try {
            // 上传文件并返回附件信息
            $file = $this->uploadFile($request);
            // 文件保存路径
            $path = $file->filepath;
            // 图片base64值
            $fp = fopen($path, 'r');
            if (!$fp) throw new LogicException('上传错误');
            $gambar = fread($fp, filesize($path));
            fclose($fp);
            //获取图片base64
            $param['Image'] = chunk_split(base64_encode($gambar));

            /** @var TencentFace $tencentFace */
            $tencentFace = app(TencentFace::class);
            $person      = $tencentFace->verifyPerson($param);
            if (!$person->IsMatch) {
                throw new LogicException('请确保是本人操作');
            }
            if ($createLog) {
                // 是本人操作储存数据
                $faceData = [
                    'user_id'    => request()->mid,
                    'attach_id'  => $file->id,
                    'scene_key'  => $request->post('scene_key', ''),
                    'scene_id'   => $request->post('scene_id', ''),
                    'scene_type' => $request->post('scene_type', ''),
                ];
                FaceVerify::create($faceData);
            }
        } catch (Throwable $exception) {
            throw new LogicException($exception->getMessage());
        }
    }

    /**
     * 删除人员
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/12/2
     *
     * @param $request
     */
    public function deletePerson($request)
    {
        try {
            $userId = strval(request()->user->id);
            $data   = $this->where('user_id', $userId)->findOrEmpty();
            if ($data->isEmpty()) {
                throw new LogicException('未查询到人脸绑定信息');
            }
            $this->verifyPerson($request, false);
            // 是本人操作，删除人脸
            $this->startTrans();
            if (!$data->delete()) {
                throw new LogicException('解绑失败');
            }
            /** @var TencentFace $tencentFace */
            $tencentFace = app(TencentFace::class);
            $tencentFace->deletePerson([
                'PersonId' => $userId
            ]);
            $this->commit();
        } catch (Throwable $exception) {
            $this->rollback();
            throw new LogicException($exception->getMessage());
        }
    }

    /**
     * 是否已经认证
     * Author: Martinsun <syh@sunyonghong.com>
     * Date: 2021/12/3
     *
     * @param $userId
     * @return int
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function isVerified($userId): int
    {
        $data   = $this->where('user_id', $userId)->findOrEmpty();

        return intval(!$data->isEmpty());
    }

}
